/**
 * Copyright (c) suzuki ryoutoku
 * See this code regarding the Apache License Version 2.0
 * @file Graphics.h
 * @author suzuki ryoutoku
 */

//=============================================================================
//	Protected multiple include file
//=============================================================================
#ifndef GRAPHICS_H
#define GRAPHICS_H

//=============================================================================
//	Preprocessor
//=============================================================================

#include <vector>
#include <list>
#include <GL/glx.h>
#include <GL/gl.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

using namespace std;


#include "Bitmap.h"
#include "include/declare.h"
#include "mathematics/Mathematics.h"
#include "mathematics/Coordinate.h"
#include "log/Log.h"
using namespace library::mathematics;
using namespace library::log;
//=============================================================================
//	define struct
//=============================================================================
/**
 * Rectangle in 3dcg, for portable windows.
 * @author suzuki ryoutoku
 * @date 2007-06-01
 * @version 1.0
 */
typedef struct tagRECT {
  unsigned long left;
  unsigned long top;
  unsigned long right;
  unsigned long bottom;
} RECT;

/**
 * Point in 3dcg, for portable windows.
 * @author suzuki ryoutoku
 * @date 2007-6-01
 * @version 1.0
 */
typedef struct tagPoint {
  unsigned long x;
  unsigned long y;
} POINT;



//=============================================================================
//	define class
//=============================================================================
/**
 * RenderingManager class is importance of graphic sysmte.
 * A RenderingManager correspond a window class(in XWindow).
 * \note
 *
 * [usage]
 * RenderingManager rm(display); // argument is XWindow's Display handle
 * rm.draw(); // calling draw 3d method.
 * 
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2007-06-01
 */
class library::graphics::RenderingManager
{
  // closedmember
private:
  Display*					 m_display;//!< XWindow Display
  Window				   m_window_id;//!< XWindow resource ID
  int 			    	m_window_width;//!< Corresponding window's width
  int				   m_window_height;//!< Corresponding window's height
  XSetWindowAttributes	   m_attribute;//!< Corresponding window's attribute
  XVisualInfo* 				  m_visual;//!< (m_window_id)'s visual infomation
  GLXContext 		   	   m_glcontext;//!< OpenGL's rendering context
  vector<Screen*>			  m_screen;//!< certainly creating one in default.
  unsigned int			 m_font_number;//!< a number of call list for font.
  XFontStruct* 					m_font;//!< font infomation.if it's null,error.
  LogManager*			 m_log_manager;//!< log manager
  ImageDataManager*				 m_idm;//!< manager of image data
  
  // opened method
public:
  RenderingManager(Display* arg, Window windowid, LogManager* arg3);
  ~RenderingManager();

  void draw();

  void resize(int width, int height);

  bool updateFont(void);

  int selectionPolygon(POINT mouse, 
					   Model* model, 
					   library::graphics::Screen* screen = NULL);
  

  // setter & getter
public:
  /**
   * @return #m_window_id
   */
  Window getM_window_id(void){
	return this->m_window_id;
  }

  Display* getM_display(void){
	return this->m_display;
  }

  /**
   * @param #m_window_height
   */
  void setM_window_height(int arg){
	this->m_window_height = arg;
  }

  /**
   * @return (RenderingManager::m_window_height)
   */
  int getM_window_height(void){
	return this->m_window_height;
  }

  /**
   * @return (RenderingManager::m_window_width)
   */
  int getM_window_width(void){
	return this->m_window_width;
  }

  /**
   * @param #m_window_width
   */
  void setM_window_width(int arg){
	this->m_window_width = arg;
  }

  /**
   * @param index index of acquiring m_screen
   * @return (RenderingManager::m_screen)[index]
   */
  Screen* getM_screen(int index){
	return this->m_screen[index];
  }

  /**
   * @return (RenderingManager::m_font_number)
   */
  unsigned int getM_font_number(void){
	return m_font_number;
  }

  /**
   * @return (RenderingManager::m_font)
   */
  XFontStruct* getM_font(void){
	return this->m_font;
  }
};




/**
 * Screen data
 * \note
 * This class is nothing to x window's screen.
 *
 * This class allow you to divid area of x window had RenderingManager.
 *
 * For example perspective lie right, 2d image lie left.
 * This have infomations, back color , camera, light  etc...
 *
 *
 * @author suzuki ryoutoku
 * @date 2007-8-28
 * @version 1.0
 */
class library::graphics::Screen 
{
  // closed member
private:
  unsigned int   	    m_type;//!< Type of the screen, says 2d or 3d
  RECT	   				m_rect;//!< Range of the screen
  RenderingManager*   	  m_rm;//!< The screen belong to RenderingManager. 
  Camera*			  m_camera;//!< camera class
  MacroCommand*	m_drawcommands;//!< command class
  vector<Light*>      m_lights;//!< light class
  
  // open enumeration
public:
  /**
   * Type of sceen
   * @author suzuki ryoutoku
   * @date 2007-8-28
   * @version 1.0
   */
  enum ScreenType{
	NONE			= 0x00, //!< no setting.
	TWO_DIMENSION	= 0x01, //!< 2d
	PERSPECTIVE		= 0x02, //!< perspective 3d
	ZPARALLEL		= 0x03, //!< orthomorphic 3d in parallel to z axis
	YPARALLEL		= 0x04, //!< orthomorphic 3d in parallel to y axis
	XZPARALLEL		= 0x05, //!< orthomorphic 3d in parallel to x axis
  };

  // opened method
public:
  Screen(const RECT& location,
		 unsigned int type = PERSPECTIVE);

  ~Screen();

  void draw(void);
  bool registGraphicalCommand(GraphicalCommand* arg);
  bool cancelGraphicalCommand(GraphicalCommand* arg);
  void createPickingViewport(float x, 
							 float y, 
							 float width, 
							 float height,
							 int viewport[4]);

 int selectionPolygon(POINT mouse, Model* model); 

  // inline setter & getter
public:
  /**
   * @retrun (library::graphics::Screen::ScreenType)
   */
  unsigned int getM_type(void)
  {
	return this->m_type;
  }

  /**
   * @param (library::graphics::Screen::m_rect)
   */
  void setM_rect(const RECT& arg)
  {
	this->m_rect = arg;
  }

  /**
   * @return (library::graphics::Screen::m_rect)
   */
  RECT* getM_rect(void)
  {
	return &(this->m_rect);
  }

  /**
   * @return (library::graphics::Screen::m_rm)
   */
  RenderingManager* getM_rm(void)
  {
	return m_rm;
  }

  /**
   * @param set (library::graphics::Screen::m_rm)
   */
  void setM_rm(RenderingManager* arg)
  {
	m_rm = arg;
  }

  /**
   * @return (Screen::m_rect.right) - (Screen::m_rect.left)
   */
  int getWidth(void)
  {
	return this->m_rect.right - this->m_rect.left;
  }

  /**
   * @return (Screen::m_rect.bottom) - (Screen::m_rect.top)
   */
  int getHeight(void)
  {
	return this->m_rect.bottom - this->m_rect.top;
  }

  Camera* getM_camera(void){return this->m_camera;}

  Light* getM_light(size_t i){return (this->m_lights[i]);}
};



/**
 * This class treat viewing infomation.
 * @author suzuki ryoutoku
 * @date 2007-8-31
 * @version 1.0
 */
class library::graphics::Camera
{
  // closed member
private:
  float	 				 m_angle;//!< field of view
  float	 				 m_front;//!< distance to font plane
  float	  				  m_back;//!< distance to back plane
  float					m_aspect;//!< aspect ratio
  Vector<double>	 m_view_position;//!< viewing position
  Vector<double> 	m_focus_position;//!< cynosure position
  Vector<double>	  m_up_direction;//!< up direction

  // opened method
public:
  Camera();
  ~Camera();
  void setupCamera(library::graphics::Screen& screen);
  bool moveToFitModel(Model* arg);

  // inline setter & getter
public:
  /**
   * @param arg (Camera::m_view_position)
   */
  void setM_view_position(const Vector<double>& arg)
  {
	this->m_view_position = arg;
  }

  /**
   * @retval (Camera::m_view_position)
   */
  Vector<double> getM_view_position(void)
  {
	return this->m_view_position;
  }
  
  /**
   * @param arg (Camera::m_focus_position)
   */
  void setM_focus_position(const Vector<double>& arg)
  {
	this->m_focus_position = arg;
  }

  /**
   * @retval (Camera::m_focus_position)
   */
  Vector<double> getM_focus_position(void)
  {
	return this->m_focus_position;
  }
  
  /**
   * @param arg (Camera::m_up_direction)
   */
  void setM_up_direction(const Vector<double>& arg){
	this->m_up_direction = arg;
  }

  /**
   * @retval (Camera::m_up_direction)
   */
  Vector<double> getM_up_direction(void){
	return this->m_up_direction;
  }
};

/**
 * This class have Lighting parameter of Open GL
 * @author r-suzuki
 * @date 2007-10-2
 * @version 1.0
 */
class library::graphics::Light 
{
  // closed member
private:
  bool				  m_state;//!<light's condition,when true light is enable
  unsigned int	  m_lightkind;//!< parallel, point, spot
  Vector<float>    m_position;//!< direction or position
  Color<float> 	  	m_ambient;//!< color of ambient
  Color<float> 	  	m_diffuse;//!< color of diffuse
  Color<float> 	   m_specular;//!< color of specular
  double		   m_constant;//!< constant damping  value from position
  double		   	 m_linear;//!< liner rate of damping from position
  double		  m_quadratic;//!< quadratic rate of damping from position
  Vector<float>	  m_direction;//!< when the class is spot, it's direction
  double		   	 m_cutoff;//!< spot's angle, if it's 180 light is disable
  double		   m_exponent;//!< rate of dumping from spot's center(exponent index)
  GLenum		  m_lightname; //!< OpenGL's index (most of computer have 8)

  // enum
public:
  enum LightKind{
	DISTANT		= 0x00,	//!< parallel light
	POINTING	= 0x01,	//!< point light
	SPOT		= 0x02,	//!< spot light
  };
  
  // opened method
public:
  Light(unsigned int index, 
		Vector<float> iposition = Vector<float>(0.0, 0.0, 1.0, 1.0), 
		Color<float> iambient = Color<float>(1.0f, 1.0f, 1.0f, 1.0f), 
		Color<float> idiffuse = Color<float>(1.0f, 1.0f, 1.0f, 1.0f), 
		Color<float> ispecular = Color<float>(1.0f, 1.0f, 1.0f, 1.0f));

  void enable(void);

  // setter & getter
public:
  /**
   * @return Light::m_state
   */
  bool getM_state(void)
  {
	return m_state;
  }
  /**
   * @param Light::m_state
   */
  void setM_state(bool arg)
  {
	m_state = arg;
  }
  /**
   * @return Light::m_position
   */
  Vector<float> getM_position(void)
  {
	return this->m_position;
  }
  /**
   * @param Light::m_position
   */
  void setM_position(const Vector<float>& arg)
  {
	this->m_position = arg;
  }

  /**
   * @return Light::m_ambient
   */
  Color<float> getM_ambient(void)
  {
	return m_ambient;
  }
  /**
   * @param Light::m_ambient
   */
  void setM_ambient(const Color<float>& arg)
  {
	m_ambient = arg;
  }
  
  /**
   * @return Light::m_diffuse
   */
  Color<float> getM_diffuse(void)
  {
	return m_diffuse;
  }
  /**
   * @param Light::m_diffuse
   */
  void setM_diffuse(const Color<float>& arg)
  {
	m_diffuse = arg;
  }
  /**
   * @return Light::m_specular
   */
  Color<float> getM_specular(void)
  {
	return m_specular;
  }
  /**
   * @param Light::m_specular
   */
  void setM_specular(const Color<float>& arg)
  {
	m_specular = arg;
  }
  /**
   * @return Light::m_constant
   */
  double getM_constant(void)
  {
	return m_constant;
  }
  /**
   * @param Light::m_constant
   */
  void setM_constant(double arg)
  {
	m_constant = arg;
  }
  /**
   * @return Light::m_linear
   */
  double getM_linear(void)
  {
	return m_linear;
  }
  /**
   * @param Light::m_linear
   */
  void setM_linear(double arg)
  {
	m_linear = arg;
  }
  /**
   * @return Light::m_quadratic
   */
  double getM_quadratic(void)
  {
	return m_quadratic;
  }
  /**
   * @param Light::m_quadratic
   */
  void setM_quadratic(double arg)
  {
	m_quadratic = arg;
  }
  /**
   * @return Light::m_direction
   */
  Vector<float> getM_direction(void)
  {
	return this->m_direction;
  }
  /**
   * @param Light::m_direction
   */
  void setM_direction(const Vector<float>& arg)
  {
	this->m_direction = arg;
  }
  /**
   * @return Light::m_cutoff
   */
  double getM_cutoff(void)
  {
	return m_cutoff;
  }
  /**
   * @param Light::m_cutoff
   */
  void setM_cutoff(double arg)
  {
	m_cutoff = arg;
  }
  /**
   * @return Light::m_exponent
   */
  double getM_exponent(void)
  {
	return m_exponent;
  }
  /**
   * @param Light::m_exponent
   */
  void setM_exponent(double arg)
  {
	m_exponent = arg;
  }
  /**
   * @return Light::m_lightname
   */
  GLenum getM_lightname(void)
  {
	return m_lightname;
  }
  /**
   * @param Light::m_lightname
   */
  void setM_exponent(GLenum arg)
  {
	m_lightname = arg;
  }
};


/**
 * super class for graphical command
 * \note
 * All graphical command class must be derived.
 * @version 1.0
 * @author suzuki ryoutoku
 */
class library::graphics::GraphicalCommand 
{
public:
  /**
   * type of graphical command 
   * \note
   * When you will define new class, add the type.
   */
  enum CommandType{
	NONE 			= 0x00,	//!< no type
	TESTCOMMAND		= 0x01, //!< test command
	MACROCOMMAND	= 0x02,	//!< macro command
	SPRITE			= 0x03,	//!< sprite
	DRAWBOX			= 0x04, //!< box
	MODEL			= 0x05, //!< 3d model
	DRAWSTRING		= 0x06, //!< string
	DRAWPOLYGONS	= 0x07, //!< polygon
  };

  // closed member
private:
  CommandType			   	 m_type;//!< type of graphical command
  RenderingManager*		m_target_rm;//!< rendering manager of target
  unsigned int	 	     m_priority;//!< drawing priority
  Coordinate	   	   m_coordinate;//!< coordinate
  int						m_state;/**< condition, enable light or 
									   drawing line, etc. 
									   Indigenous infomation of derived class. 
									*/
    
  // opened method
public:
  GraphicalCommand(CommandType arg = NONE);
  virtual ~GraphicalCommand();

  /**
   * execute drawing, Derived class must override!
   * @param screen screen of target
   * @author suzuki ryoutoku
   * @date 2007-6-3
   */
  virtual int execute(Screen* screen) = 0;

  // calling by (Screen::registGraphicalCommand)
  virtual void assignTargetRenderingManager(RenderingManager* arg);

  // setter & getter (inline)
public:
  /**
   * @return #m_type
   */
  CommandType getM_type()
  {
	return this->m_type;
  }

  /**
   * @param arg #m_type
   */
  void setM_type(CommandType arg)
  {
	this->m_type = arg;
  }

  /**
   * @return #m_priority
   */
  unsigned int getM_priority(void)
  {
	return this->m_priority;
  }

  /**
   * @param arg GraphicalCommand::m_state
   */
  void setM_state(int param)
  {
	this->m_state = param;
  }

  /**
   * @return GraphicalCommand::m_state
   */
  int getM_state(void)
  {
	return this->m_state;
  }

  /**
   * @param arg #m_priority
   */
  void setM_priority(unsigned int arg)
  {
	this->m_priority = arg;
  }

  /**
   * @return #m_target_rm
   */
  RenderingManager* getM_target_rm(void)
  {
	return this->m_target_rm;
  }

    
  /**
   * @return GraphicalCommand::m_coordinate
   */
  Coordinate* getM_coordinate(void)
  {
	return &(this->m_coordinate);
  }

    // public enum member
public:
  /**
   * type of drawing method
   * @author r-suzuki
   * @date 2007-10-8
   * @version 1.0
   */
  enum DrawingState{
	WIRE_FRAME	= 0x01, //!< enable drawing line 
	LIGHTING	= 0x10, //!< enable lighting
  };

};

/**
 * Test command
 * \note 
 * You can equip this class's instance with original function.
 * Original function is called inside RenderingManager::draw.
 * @author suzuki ryoutoku 
 * @date 2007-9-8
 * @version 1.0
 */
class library::graphics::TestCommand
  : public library::graphics::GraphicalCommand
{
  // closed member
private:
#if 0
  Vector<double>	m_vertex[8];
  int		 m_face_index[6][4];
  Color<float>		 m_color[6];
  Vector<double>	m_normal[6];
#endif
  void		  (*m_function)(Screen* screen);

  // opened method
public:
  TestCommand(GraphicalCommand::CommandType arg = TESTCOMMAND);
  ~TestCommand();

  virtual int execute(Screen* screen);
  void setOriginalFunction(void (*function)(Screen* screen));
  
  // inline setter & getter
public:

};



/**
 * macro command
 * \note
 * this class is enable nesting graphical command.
 * @author suzuki ryoutoku
 * @version 1.0
 */
class library::graphics::MacroCommand 
  : public library::graphics::GraphicalCommand 
{
  // closed member
private:
  list<GraphicalCommand*> m_commands; //!< nesting container
  
  // opened method
public:
  MacroCommand(GraphicalCommand::CommandType arg 
			   = GraphicalCommand::MACROCOMMAND);
  ~MacroCommand();
  int execute(Screen* screen);
  int append(GraphicalCommand* arg);
  bool cancel(GraphicalCommand* arg);
#if 0
  bool removeCommand(GraphicalCommand* arg);
#endif
  
  // inline setter & getter
public:
  unsigned int getCommandSum(void){return this->m_commands.size();}
};


/**
 * sprite class, this class allow you to print bitmap image in 3d screen.
 * \note
 * This class arrow you to blend alpha value. 
 * If you want to create transparent image,  then specify transparency pixel 
 * color is black.
 * Attention, If you don't call setScreenSize, therefore no drawing.
 * \n
 * [usage]\n
 * sprite = new Sprite(); \n
 * sprite->setScreenSize(ScreenSize, ScreenSize); \n
 * sprite->setTransmission(0,0,0); \n
 * sprite->setPoint(0, 0); \n
 * \n
 * sprite->execute(); \n
 * \n
 * 
 * @version 1.0
 * @author suzuki ryoutoku
 */
class library::graphics::Sprite 
  : public library::graphics::GraphicalCommand
{
  // closed member
private:
  POINT					m_point;//!< sprite's pivot point
  RECT 				  	 m_rect;//!< sprite's image range
  Color<float>			m_color;//!< sprite's polgon color
  unsigned int 			m_texid;//!< when it's 0xFFFFFFFF, no use.
  Vector2D<float>		m_uv[4];//!< uv values

  // opened method
public:
  Sprite(GraphicalCommand::CommandType arg = GraphicalCommand::SPRITE);
  ~Sprite();
  
  virtual int execute(Screen* screen);
  void setM_rect(int ileft, int itop, int iwidth, int iheight);
  void setPoint(int ileft, int itop);
  bool insideSprite(POINT arg);
  void setTextureImage(ImageData* image);


  // setter & getter (inline)
public:
#if 0
  /**
   * @param arg set #m_texid
   */
  void setM_texid(unsigned int arg)
  {
	this->m_texid = arg;
  }
#endif

  /**
   * @return #m_texid
   */
  unsigned int getM_texid(void)
  {
	return this->m_texid;
  }

  
  /**
   * @param arg set #m_color
   */
  void setM_color(const Color<float>& arg)
  {
	this->m_color = arg;
  }
  

};


/**
 * Image data.
 * @version 1.0
 * @date 2007-05-22
 * @author suzuki ryoutoku
 */
class library::graphics::ImageData
{
  // closed member
private:
  unsigned int 			m_texid;//!< (if 0xFFFFFFFF is not regist OpenGL)
  unsigned int 	  *m_bitpattern;//!< bitmap's pixel pattern
  unsigned int 			m_width;//!< width of bitmap file's pixel pattern
  unsigned int 	 	   m_height;//!< height of bitmap file's pixel pattern
  unsigned int	 m_memory_width;//!< assured memory width in fact
  unsigned int	m_memory_height;//!< assure memory height in fact
  char* 	 		  	 m_name;//!< bitmap file's name

  // opened member
public:
  ImageData(const char *name = NULL, 
			const BITMAPINFO* info = NULL, 
			const unsigned int* bittpattern = NULL);
  ~ImageData();
  
  bool setPixel(const unsigned int& x, 
				const unsigned int& y,
				const unsigned char& R, 
				const unsigned char& G,
				const unsigned char& B, 
				const unsigned char& A);
  bool setPixel(const unsigned int& x, 
				const unsigned int& y,
				const unsigned int pixel);
  
  bool getPixel(const unsigned int& x, 
				const unsigned int& y,
				unsigned int* rgba);

  // closed method
private:
  bool isPowerOf2(void);
  
  bool setBitmapBufferMemory(int iwidth, int iheight);

  void setTransmission(unsigned int R, unsigned int G, unsigned int B);


  // setter & getter
public:
  void setM_name(const string& arg);

  /**
   * @return #m_name
   */
  const char* getM_name(void)
  {
	return this->m_name;
  }

  /**
   * @return #m_memory_width
   */
  unsigned int getM_memory_width(void)
  {
	return this->m_memory_width;
  }

  /**
   * @return #m_memory_height
   */
  unsigned int getM_memory_height(void)
  {
	return this->m_memory_height;
  }
  
  /**
   * @return #m_bitpattern
   */
  unsigned int* getM_bitpattern(void)
  {
	return this->m_bitpattern;
  }

  /**
   * @param arg set #m_texid
   */
  void setM_texid(unsigned int& arg)
  {
	this->m_texid =arg;
  }

  /**
   * @return #m_texid
   */
  unsigned int getM_texid(void)
  {
	return this->m_texid;
  }

  /**
   * @return #m_width
   */
  unsigned int getM_width(void)
  {
	return this->m_width;
  }

  /**
   * @return #m_height
   */
  unsigned int getM_height(void)
  {
	return this->m_height;
  }

  // opened class method
public:
  static bool LoadBitMapFileHeader(FILE* fp, BITMAPFILEHEADER* header);
  static bool LoadBitMapFileHedaerInfo(FILE* fp, BITMAPINFO* info);
  static bool LoadBitMapFile24BitPattern(FILE* fp, 
										 ImageData* image,
										 BITMAPFILEHEADER* header, 
										 BITMAPINFO* info);

  // friend class
public:
  friend class library::graphics::ImageDataManager;
};


/**
 * Manager of (ImageData)
 * \note
 * This class manage texuture image.
 * @author suzuki ryoutoku
 * @date 2007-6-10
 * @version 1.0
 */
class library::graphics::ImageDataManager
{
  // closed member
private:
  list<library::graphics::ImageData*>   m_imagedatas; //!< container of image data

  // closed method
private:
  ImageDataManager();

  // opened method
public:
  ~ImageDataManager();
  unsigned int createImageData(const string& filepass);
  unsigned int getTexId(const string& filepass);
  unsigned int  assignTexId(ImageData*);
  ImageData* getImageData(unsigned int texid);
  bool cancelImageData(ImageData* arg);
  unsigned int setTransmission(ImageData* arg, 
							   unsigned int R = 0,
							   unsigned int G = 0, 
							   unsigned int B = 0);

  // static method
public:
  static ImageDataManager* getInstance(void);

  // static member
private:
  static ImageDataManager instance;
};


/**
 * This class is drawing Box
 * @author suzuki ryoutoku 
 * @date 2007-9-8
 * @version 1.0
 */
class library::graphics::DrawBox
  : public library::graphics::GraphicalCommand
{
  // closed member
private:
  Vector<double>	 m_coord[8];
  int		 m_face_index[6][4];
  Color<float>		 m_color[6];
  Vector<double>	m_normal[6];

  // opened method
public:
  DrawBox(GraphicalCommand::CommandType arg = GraphicalCommand::DRAWBOX);
  ~DrawBox();

  virtual int execute(Screen* screen);
  
  // inline setter & getter
public:
  /**
   * @param i coord index 
   * @return m_vertex
   */
  Vector<double> getM_coord(int i){
	return this->m_coord[i];
  }

  /**
   * @param i coord index
   * @param arg vector set to vertex 
   */
  void setM_coord(int i, const Vector<double>& arg){
	this->m_coord[i] = arg;
  }

  
  /**
   * @return m_face
   */
  int getM_face_index(int i, int j ){
	return this->m_face_index[i][j];
  }

  /**
   * @param i
   * @param j
   * @param arg
   */
  void setM_face_index(int i, int j, int arg){
	this->m_face_index[i][j] = arg;
  }
};

/**
 * This class allow you to draw character string in 3d screen.
 * \note
 * Only english character.
 * @author suzuki ryoutoku 
 * @date 2007-10-20
 * @version 1.0
 */
class library::graphics::DrawString
  : public library::graphics::GraphicalCommand
{
  // closed member
private:
  char		m_message[256];
  int		 m_line_number;
  
  // opened method
public:
  DrawString(GraphicalCommand::CommandType arg = GraphicalCommand::DRAWSTRING);
  ~DrawString();

  void setM_message(char* arg);
  
  virtual int execute(Screen* screen);

  // inline setter & gettter
public:
  /**
   * @param (DrawString::m_line_number)
   */
  void setM_line_number(int arg)
  {
	this->m_line_number = arg;
  }
};


/**
 * Group data of 3d model.
 * \note
 * Group is component Volume is polygon soup.
 * In addtion to have strip index.
 * 
 * Polygon and line consist of vertex index, restate consist of 
 * only connectivity infomation.
 * This class use global index as normal vector index.
 *
 * @author r-suzuki
 * @date 2007-10-11
 * @version 1.0
 */
class library::graphics::Group
{
  // closed method
private:
  int				  m_index;//!< Group index in 3d model
  int			  m_attribute;/**< 
								 This member represent selectable drawing
								 methods by using bit flag.
								 If no bit (0x00) is only vertex array.
								 0x01 is enable texturing.
								 0x10 is enable drawing triabgle strip.
							  */
  unsigned int	m_draw_method;//!< Please see enum DrawingMethodType.
  int				  m_texid;//!< texture id
  char m_texturefilename[256];//!< Texture file name
  Color<float>		  m_color;//!< group color's color

  int			   m_face_sum;//!< face sum, triangle sum + quadrangle sum
  int			m_segment_sum;//!< line sum
  int*			   	m_segment;//!< line's connectivity(two)

  int		   m_triangle_sum;//!< triangle sum
  int*			   m_triangle;//!< triangle's connectivity(three)
  int*	  m_triangle_globalid;//!< triangle's index of normal vector

  int		 m_quadrangle_sum;//!< quadrangle sum
  int*			 m_quadrangle;//!< quadrangle's connectivity
  int*	m_quadrangle_globalid;//!< equal quadrangle's index of normal vector

  Color<float>*	m_strip_color;//!< strip's color
  int			  m_strip_sum;//!< triangle strip sum
  int*		   m_strip_length;//!< length is each triangle strip
  int**		 m_relative_index;//!< relate to triangle to each strip component  
  int**			m_strip_index;//!< strip component (vertex index)
  

  // opened method
public:
  Group();
  ~Group();

  bool initialize(int triangle_sum, int quadrangle_sum);

  void setM_draw_method(unsigned int arg);

  void toggleStripAttribute(void);

  // inline setter & getter & method
public:
  void setM_color(Color<float> arg){this->m_color = arg;}

  int getM_face_sum(){return m_face_sum;}

  void setM_index(int arg){m_index=arg;}
  int getM_index(){return m_index;}

  void setM_texturefilename(char* arg){strcpy(m_texturefilename,arg);}

  int getM_attribute(void){return this->m_attribute;}
  //  void setM_attribute(int param){this->m_attribute = param;}

  unsigned int getM_draw_method(void){return this->m_draw_method;}

  int getM_triangle_sum(){return m_triangle_sum;}
  int* getM_triangle(){return m_triangle;}

  int* getM_triangle_globalid(){return m_triangle_globalid;}

  void setM_strip_sum(int arg){this->m_strip_sum = arg;}

  void setM_strip_length(int* arg){this->m_strip_length = arg;}

  int* getM_strip_length(void){return this->m_strip_length;}

  void setM_relative_index(int** relative){this->m_relative_index = relative;}
  int** getM_relative_index(void){return this->m_relative_index;}

  void setM_strip_index(int** arg){this->m_strip_index = arg;}
  int** getM_strip_index(void){return this->m_strip_index;}

  void setM_strip_color(Color<float>* arg){this->m_strip_color = arg;}

  void toggleNoDrawing(void){this->m_attribute ^= NO_DRAWING;}

  // friend class
public:
  friend class library::graphics::Model;
  friend class library::graphics::ReadPcm;
  friend class library::graphics::ReadObj;
  friend class library::graphics::Read3ds;

  // enum type
public:
  enum DrawingMethodType{
	DRAW_DEFAULT = 0x00,
	DRAW_WITH_STRIP = 0x02,
	DRAW_WITH_SEPARATE_COLOR_STRIP = 0x04,
	DRAW_TEXTURE_MAPPING = 0x05,
	DRAW_TEXTURE_MAPPING_WITH_STRIP = 0x06,
  };
  enum SelectableDrawingAttribute{
	VERTEX_ARRAY = 0x00,
	TEXTURE_MAPPING = 0x01,
	STRIP = 0x10,
	NO_DRAWING = 0x100,
  };
};

/**
 * Volume data of 3d model.
 * \note
 * Volume is polygon soup.
 * It have a number of group.
 * @author r-suzuki
 * @date 2007-10-12
 * @version 1.0
 */
class library::graphics::Volume
{
  // closed member
private:
  int				m_index;//!< volume's index
  int				m_state;/**< 
							   This member is state of drawing condition.
							   When it's 0x00 is enable to draw.
							   When it's 0x01 is diable to draw.
							*/
  char			m_name[256];//!< volume's name
  int			m_group_sum;//!< group sum
  Group*			m_group;//!< group data

  // opened method
public:
  Volume();
  ~Volume();

  // inline setter & getter
public:
  /**
   * @return (Volume::m_name)
   */
  char* getM_name(void)
  {
	return this->m_name;
  }

  /**
   * @return (Volume::m_group_sum)
   */
  int getM_group_sum(void){return this->m_group_sum;}
  void setM_group_sum(int arg){this->m_group_sum=arg;}

  /**
   * @return (Volume::m_group)
   */
  Group* getM_group()
  {
	return this->m_group;
  }

  int getM_state(void){return this->m_state;}
  void setM_state(int param){this->m_state = param;}

public:
  friend class library::graphics::Model;
  friend class library::graphics::ReadPcm;
  friend class library::graphics::ReadObj;
  friend class library::graphics::Read3ds;
};


/**
 * This class represent 3d model data.
 * \note
 * What is 3d model data?
 * It consists of volume datas are polygon soup.
 * These volume datas don't be hierarchy data.
 *
 * @author suzuki ryoutoku 
 * @date 2007-9-8
 * @version 1.0
 */
class library::graphics::Model
  : public library::graphics::GraphicalCommand
{
  // closed member
private:
  bool				m_strip_flag;//!< make strip or not
  int				m_vertex_sum;//!< a number of vector
  int				m_normal_sum;/**< 
									This is a number of normal sum, 
									and equal face sum.
								 */
  int					m_uv_sum;//!< a number of uv array
  int				 m_point_sum;//!< a number of point array
  int				m_volume_sum;//!< volume sum
  Vector<double>*		m_vertex;//!< vertex coord array
  Vector<double>*		m_normal;//!< normal vector array
  Vector2D<float>*			m_uv;//!< uv coord array
  Point*				 m_point;//!< This array has index of m_uv and m_vertex
  Volume*				m_volume;//!< volume list


  // opened method
public:
  Model(bool flag = false, 
		GraphicalCommand::CommandType arg = GraphicalCommand::MODEL);
  ~Model();

  virtual int execute(Screen* screen);

  Volume* getM_volume_with_name(char* name);
  int createNormalVector(void);
  void createCenter(void);
  void selectionPolygon(void);
  Polygon queryPolygon(int globalid);
  void computeSize(double* width, double* height, double* depth);
  unsigned int getNumberOfGroups(void);

  void setTextureID(ImageDataManager* idm);

  void coloring(Color<float> color);

  unsigned int getFaceSum(void);

  // inline setter & getter
public:
  bool getM_strip_flag(void){return this->m_strip_flag;}
  void setM_strip_flag(bool arg){this->m_strip_flag=arg;}

  int getM_volume_sum(void){return this->m_volume_sum;}

  int getM_vertex_sum(void){return m_vertex_sum;}

  Vector<double>* getM_vertex(void){return m_vertex;}
  
  Volume* getM_volume(){return this->m_volume;}

  int getM_normal_sum(){return this->m_normal_sum;}
  Vector<double>* getM_normal(){return this->m_normal;}

  void setM_uv_sum(int arg){m_uv_sum=arg;}
  void setM_uv(Vector2D<float>* arg){m_uv=arg;}

  // friend class
public:
  friend class library::graphics::Reader;
  friend class library::graphics::ReadPcm;
  friend class library::graphics::ReadObj;
  friend class library::graphics::Read3ds;
};

/**
 * This class's feature is drawing polygon.
 * \note
 * Keynote of this class is the way to manage a vertex data and coordinate.
 * The way is two, to lease from model class or to allocate for this class.
 *
 * If the member names lease_flag is true, It leases vertex data and coordinate
 * from model data.
 *
 * @author suzuki ryoutoku
 * @date 2007-12-29
 * @version 1.0
 */
class library::graphics::DrawPolygons
  : public library::graphics::GraphicalCommand
{
private:
  library::graphics::Model*	  m_target_model;
  bool							m_lease_flag;
  Vector<double>*					m_vertex;
  Vector<double>*					m_normal;
  list<Polygon>	   				   m_polygon;


public:
  DrawPolygons(bool arg1 = false,
			   Vector<double>* arg2 = NULL,
			   Vector<double>* arg3 = NULL,
			   library::graphics::Model* arg4 = NULL,
			   GraphicalCommand::CommandType arg 
			   = GraphicalCommand::DRAWPOLYGONS);
  ~DrawPolygons();

public:
  bool addPolygon(Polygon);
  bool removePolygon(int);
  bool removeAllPolygon(void);
  Polygon getPolygon(int);

  virtual int execute(Screen* screen);
};


/**
 * Only connectivity infomation.
 * \note
 * This program express quadric.
 * @author suzuki ryoutoku
 * @date 2007-12-29
 * @version 1.0
 */
class library::graphics::Polygon
{
private:
  int	   	   m_global_id;//!< global index of polygon in 3d model
  unsigned int		m_size;//!< sum vertex to compose polygon 
  int	 m_connectivity[4];//!< vertex index to compose polygon

public:
  Polygon(int arg1, int arg2);
  Polygon(const Polygon& arg);
  ~Polygon();

  void displayInConsole(void);

  //getter & setter
public:
  int getM_global_id(void){return this->m_global_id;}
  void setM_global_id(int arg){this->m_global_id = arg;}
  int getM_size(void){return this->m_size;}
  void setM_connectivity(unsigned int index, int value);
  int getM_connectivity(unsigned int index);

public:
  friend class DrawPolygons;
};


//=============================================================================
//	Include gard
//=============================================================================
#endif
